package com.naiterui.ehp.bs.emr.service.impl;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.google.common.collect.Lists;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.consult.VideoConsultBO;
import com.naiterui.ehp.bp.bo.consult.VideoConsultMessageBO;
import com.naiterui.ehp.bp.bo.im.SessionDetailBO;
import com.naiterui.ehp.bp.bo.im.SessionParamBO;
import com.naiterui.ehp.bp.bo.patient.PatientInquirerBO;
import com.naiterui.ehp.bp.bo.recommend.DrPointPrescriptionBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomItemBO;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.emr.dto.MedicalRecordDetailDTO;
import com.naiterui.ehp.bs.emr.dto.PatientInfoDTO;
import com.naiterui.ehp.bs.emr.feign.IDoctorFeignClient;
import com.naiterui.ehp.bs.emr.feign.IMFeignClient;
import com.naiterui.ehp.bs.emr.feign.IPatientFeignClient;
import com.naiterui.ehp.bs.emr.feign.IRecommendFeignClient;
import com.naiterui.ehp.bs.emr.feign.VideoConsultFeignClient;
import com.naiterui.ehp.bs.emr.service.IMedicalRecordService;
import com.naiterui.ehp.bs.emr.service.IOpenEmrService;
import com.naiterui.ehp.bs.emr.service.IPatientCaseService;
import com.naiterui.ehp.bs.emr.vo.PatientConsultRecordVO;
import com.naiterui.ehp.bs.emr.vo.openapi.ConsultRecordDetailVO;
import com.naiterui.ehp.bs.emr.vo.openapi.ConsultRecordPrVO;
import com.naiterui.ehp.bs.emr.vo.openapi.ConsultRecordVO;
import com.naiterui.ehp.bs.emr.vo.patient.PatientCaseDetailVO;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 对外诊疗记录业务层实现
 *
 * @author guoyongxiang
 * @version 1.0.0
 * @date 2021/7/7 13:24
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class OpenEmrServiceImpl implements IOpenEmrService {

    private final IPatientFeignClient patientFeignClient;
    private final IMFeignClient imFeignClient;
    private final IRecommendFeignClient recommendFeignClient;
    private final IMedicalRecordService medicalRecordService;
    private final IPatientCaseService patientCaseService;
    private final IDoctorFeignClient doctorFeignClient;
    private final VideoConsultFeignClient videoConsultFeignClient;

    @Override
    public PageVO<ConsultRecordVO> getCaseList(String idcard, PageParamVO pageParamVO) throws BusinessException {
        // 查询身份证关联的就诊人ID
        List<Long> inquirerIds = patientFeignClient.getInquirerIdsByIdcard(idcard);
        if (CollectionUtils.isEmpty(inquirerIds)) {
            log.info("就诊记录列表查询, 身份证号无对应的就诊人记录 idcard:{}", idcard);
            return PageVO.newBuilder().totalCount(0).pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum()).result(Lists.newArrayList()).build();
        }

        // 查询就诊人相关病例列表
        PageVO<SessionDetailBO> sessionPageVO = imFeignClient.sessionList(SessionParamBO.builder().pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum()).inquirerIds(inquirerIds).containRecord(1).build());
        List<String> sessionIds = sessionPageVO.getResult().stream().map(SessionDetailBO::getSessionId).collect(Collectors.toList());

        // 查询病例会话相关处方列表
        if (CollectionUtils.isEmpty(sessionIds)) {
            log.info("就诊记录列表查询, 暂无会话记录 idcard:{}", idcard);
            return PageVO.newBuilder().totalCount(0).pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum()).result(Lists.newArrayList()).build();
        }


        List<MedicalRecordDetailDTO> recordDetails = medicalRecordService.findBySessionIds(sessionIds);
        if (CollectionUtils.isEmpty(sessionIds)) {
            log.info("就诊记录列表查询, 病例未绑定会话 idcard:{}", idcard);
            return PageVO.newBuilder().totalCount(0).pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum()).result(Lists.newArrayList()).build();
        }

        Map<String, List<MedicalRecordDetailDTO>> recordMap = recordDetails.stream().filter(r -> !StringUtils.isEmpty(r.getSessionId())).collect(Collectors.groupingBy(MedicalRecordDetailDTO::getSessionId));
        Map<String, List<MedicalRecordDetailDTO>> finalRecordMap = recordMap;

        List<ConsultRecordVO> list = sessionPageVO.getResult().stream().map(s -> {
            List<MedicalRecordDetailDTO> records = finalRecordMap.get(s.getSessionId());
            MedicalRecordDetailDTO recordDetail = records != null && records.size() > 0 ? records.get(0) : null;
            String diagnosis = recordDetail == null ? "" : recordDetail.getRecord().getDiagnosisList().stream().collect(Collectors.joining(","));
            return ConsultRecordVO.builder()
                    .sessionId(s.getSessionId())
                    .vistingTime(s.getBeginTime())
                    .doctorName(recordDetail.getDoctorName())
                    .departmentName(recordDetail.getDepartmentName())
                    .diagnosis(diagnosis)
                    .name(Optional.ofNullable(recordDetail).map(MedicalRecordDetailDTO::getPatientInfo).map(PatientInfoDTO::getName).orElse("")).build();
        }).collect(Collectors.toList());

        return PageVO.newBuilder().totalCount(sessionPageVO.getTotalCount()).pageNo(sessionPageVO.getPageNo()).pageSize(sessionPageVO.getPageSize()).result(list).build();
    }

    @Override
    public ConsultRecordDetailVO getCaseDetail(String idcard, String sessionId) throws BusinessException {
        // 查询会话相关病例列表
        List<MedicalRecordDetailDTO> recordDetails = medicalRecordService.findBySessionIds(Lists.newArrayList(sessionId));
        MedicalRecordDetailDTO recordDetailDTO = recordDetails.get(0);
        Assert.notNull(recordDetailDTO, "病例信息不存在");

        List<PatientInquirerBO> inquirerBOS = patientFeignClient.getPatientInquirer(Lists.newArrayList(recordDetailDTO.getPatientInfo().getInquirerId()));
        PatientInquirerBO inquirerBO = !CollectionUtils.isEmpty(inquirerBOS) ? inquirerBOS.get(0) : null;
        Assert.notNull(inquirerBO, "就诊人信息不存在或已被删除");

        Long consultSessionId = doctorFeignClient.consultSessionId(sessionId);
        List<MedicationRecomBO> recoms = recommendFeignClient.getRecomSessionList(String.valueOf(consultSessionId));
        List<Long> recomIds = recoms.stream().map(MedicationRecomBO::getId).collect(Collectors.toList());

        List<ConsultRecordPrVO> prList = this.getConsultRecordPrs(recomIds);

        // 查询病例会话相关处方列表
        return ConsultRecordDetailVO.builder()
                .sessionId(sessionId)
                .phone(inquirerBO.getContactPhone())
                .caseDetail(patientCaseService.covertToCaseDetail(recordDetailDTO))
                .prescriptions(prList).build();
    }

    @Override
    public PageVO<ConsultRecordVO> getVideoCaseList(String idcard, PageParamVO pageParamVO) throws BusinessException {
        // 查询身份证关联的就诊人ID
        List<Long> inquirerIds = patientFeignClient.getInquirerIdsByIdcard(idcard);
        if (CollectionUtils.isEmpty(inquirerIds)) {
            log.info("就诊记录列表查询, 身份证号无对应的就诊人记录 idcard:{}", idcard);
            return PageVO.newBuilder().totalCount(0).pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
                .result(Lists.newArrayList()).build();
        }
        List<PatientInquirerBO> inquirerBOS =
            patientFeignClient.getPatientInquirer(inquirerIds);

        Map<Long, String> inquirerBOMap = inquirerBOS.stream()
            .collect(Collectors.toMap(PatientInquirerBO::getInquirerId, PatientInquirerBO::getName, (a, b) -> a));
        log.info("就诊记录 inquirerBOMap：{}", JsonMapper.toJson(inquirerBOMap));
        PageVO<PatientConsultRecordVO> recordVOPage =
            videoConsultFeignClient.getVideoConsultsPage(pageParamVO.getPage(), pageParamVO.getNum(), inquirerIds);

        // 查询病例会话相关处方列表
        if (CollectionUtils.isEmpty(recordVOPage.getResult())) {
            log.info("就诊记录列表查询, 暂视频问诊记录 idcard:{}", idcard);
            return PageVO.newBuilder().totalCount(0).pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
                .result(Lists.newArrayList()).build();
        }
        List<ConsultRecordVO> records = recordVOPage.getResult().stream()
            .map(c -> ConsultRecordVO.builder().videoConsultId(c.getVideoConsultId())
                .vistingTime(c.getConsultTime().getTime()).name(inquirerBOMap.get(c.getInquirerId()))
                .doctorName(c.getName())
                .departmentName(c.getDepartment()).diagnosis(c.getDiagnosis()).build())
            .collect(Collectors.toList());

        return PageVO.newBuilder().totalCount(recordVOPage.getTotalCount()).pageNo(recordVOPage.getPageNo())
            .pageSize(recordVOPage.getPageSize()).result(records).build();
    }

    @Override
    public ConsultRecordDetailVO getVideoCaseDetail(String idcard, Long videoConsultId) throws BusinessException {

        // 查询身份证关联的就诊人ID
        List<Long> inquirerIds = patientFeignClient.getInquirerIdsByIdcard(idcard);
        if (CollectionUtils.isEmpty(inquirerIds)) {
            log.warn("就诊记录列表查询, 身份证号无对应的就诊人记录 idcard:{}", idcard);
            Assert.notEmpty(inquirerIds, "身份证号无对应的就诊人记录");
        }
        VideoConsultBO videoConsult = videoConsultFeignClient.getVideoConsult(videoConsultId);
        Assert.notNull(videoConsult, "视频记录不存在");
        List<VideoConsultMessageBO> messages =
            videoConsultFeignClient.getMessageByVideoConsultId(videoConsultId, Lists.newArrayList(
                VideoConsultMessageBO.VIDEO_CONSULT_TYPE_TO_DRCASE, VideoConsultMessageBO.VIDEO_CONSULT_TYPE_TO_RECOM));

        List<PatientInquirerBO> inquirerBOS =
            patientFeignClient.getPatientInquirer(Lists.newArrayList(videoConsult.getInquirerId()));
        PatientInquirerBO inquirerBO = !CollectionUtils.isEmpty(inquirerBOS) ? inquirerBOS.get(0) : null;
        Assert.notNull(inquirerBO, "就诊人信息不存在或已被删除");

        List<String> casesIds =
            messages.stream().filter(m -> VideoConsultMessageBO.VIDEO_CONSULT_TYPE_TO_DRCASE == m.getType())
                .map(VideoConsultMessageBO::getContent).collect(Collectors.toList());
        List<Long> recomIds =
            messages.stream().filter(m -> VideoConsultMessageBO.VIDEO_CONSULT_TYPE_TO_RECOM == m.getType())
                .map(VideoConsultMessageBO::getContent).map(Long::valueOf).collect(Collectors.toList());

        List<String> diagnosisList = Lists.newArrayList();

        List<MedicalRecordDetailDTO> recordDetails = medicalRecordService.findByIds(casesIds);
        PatientCaseDetailVO caseDetailVO;
        PatientConsultRecordVO recordVO = videoConsultFeignClient.getPatientConsultRecord(videoConsultId);
        if (CollectionUtils.isEmpty(recordDetails)) {
            caseDetailVO = new PatientCaseDetailVO();
            caseDetailVO.setName(inquirerBO.getName());
            caseDetailVO.setGender(inquirerBO.getGender());
            caseDetailVO.setAge(inquirerBO.getAge());

            caseDetailVO.setDoctorName(recordVO.getName());
            caseDetailVO.setDepartmentName(recordVO.getDepartment());
            caseDetailVO.setHospitalName(ConfigUtil.getString("ehp.hospital.name"));
            if (!StringUtils.isEmpty(recordVO.getDiagnosis())) {
                String[] diagnosisArr = recordVO.getDiagnosis().split(",");
                diagnosisList.addAll(Arrays.stream(diagnosisArr).collect(Collectors.toList()));
            }

        } else {
            caseDetailVO =
                Optional.ofNullable(recordDetails.get(0)).map(r -> patientCaseService.covertToCaseDetail(r))
                    .orElse(null);
            if (caseDetailVO != null && caseDetailVO.getDoctorMedicalRecord() != null) {
                diagnosisList.addAll(caseDetailVO.getDoctorMedicalRecord().getDiagnosisList());
            }
        }

        List<ConsultRecordPrVO> prList = this.getConsultRecordPrs(recomIds);
        prList.stream().forEach(p -> {
            if (!StringUtils.isEmpty(p.getDiagnosis())) {
                String[] diagnosisArr = p.getDiagnosis().split(",");
                diagnosisList.addAll(Arrays.stream(diagnosisArr).collect(Collectors.toList()));
            }
        });

        // 查询病例会话相关处方列表
        return ConsultRecordDetailVO.builder().videoConsultId(videoConsultId)
            .phone(inquirerBO.getChildTag() == 1 ? inquirerBO.getGuardianPhone() : inquirerBO.getPhone())
            .vistingTime(recordVO.getConsultTime().getTime())
            .caseDetail(caseDetailVO).diagnosis(diagnosisList.stream().distinct().collect(Collectors.joining(",")))
            .prescriptions(prList).build();
    }

    private List<ConsultRecordPrVO> getConsultRecordPrs(List<Long> recomIds) throws BusinessException {
        List<ConsultRecordPrVO> prList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(recomIds)) {
            List<DrPointPrescriptionBO> recoms = recommendFeignClient
                .getPrescriptionList(recomIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
            recoms.stream().forEach(r -> {
                // 处理处方药品明细
                List<MedicationRecomItemBO> detials = r.getItems();
                List<ConsultRecordPrVO.Item> items =
                    detials.stream().map(d -> ConsultRecordPrVO.Item.builder().name(d.getName())
                        .quantity(d.getQuantity()).usages(d.getUsages()).build()).collect(Collectors.toList());
                prList.add(ConsultRecordPrVO.builder().diagnosis(r.getDiagnosis()).serialNumber(r.getSerialNumber())
                    .items(items).build());
            });
        }
        return prList;
    }
}
